﻿using System;
using System.Data;
using System.Configuration;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Security.Policy;
using System.IO;
using System.Collections.Generic;
using net.veekee.common.data;

namespace net.veekee.common.rules
{
    public class RuleSet<C, T> where T : AnEntry
    {
        private RuleDynamicClass dynamic = null;

        public String RuleFileName { get; set; }

        public String Name { get { return this.dynamic.ClassName; } }

        public int Salience { get { return this.dynamic.Salience; } }

        public bool IsValid { get { return this.dynamic.Status == DynamicClassStatus.Valid && this.rule != null; } }

        public DynamicClassStatus Status { get { return this.dynamic.Status; } }

        private long statsProcessedNumber = 0;
        public long StatsProcessedNumber { get { return this.statsProcessedNumber; } }

        private ARuleDynamicClass<C, T> rule = null;

        public RuleSet()
        {
            this.dynamic = new RuleDynamicClass(typeof(C).FullName, typeof(T).FullName);
            this.dynamic.AddImport(typeof(C).Namespace);
            this.dynamic.AddImport(typeof(T).Namespace);
        }

        public void Load(List<RuleSetLine> content)
        {
            try
            {
                this.dynamic.Status = DynamicClassStatus.Unknown;
                this.dynamic.SetRuleFileName(this.RuleFileName);
                foreach (RuleSetLine line in content)
                {
                    this.LoadNewEntry(line.Line, line.Content);
                }
                if (this.dynamic.EOR)
                {
                    this.dynamic.Compile();
                    ARuleDynamicClass<C, T> newRule = this.dynamic.Create() as ARuleDynamicClass<C, T>;
                    if (newRule != null)
                    {
                        this.rule = newRule;
                        this.dynamic.Status = this.rule.GetStatus();
                        if (! this.IsValid)
                        {
                            Log.GetInstance().Info("Dynamic class {0} has been flaged as {1}", this.dynamic.GetType().FullName, this.dynamic.Status.ToString());
                        }
                    }
                }
                else
                    Log.GetInstance().Error("A rule was not loaded as 'end' tag couldn't be found.");
            }
            catch (Exception e)
            {
                Log.GetInstance().Error(e.ToString());
            }
            finally
            {
            }
        }

        public bool CheckConditions(C context, T obj)
        {
            try
            {
                return this.rule.CheckConditions(context, obj);
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("An error occured while checking for conditions on type {0}: {1}", typeof(T).FullName, e.ToString());
            }
            return false;
        }

        public void Process(C context, T obj)
        {
            try
            {
                obj.TriggeredRules.Add(this.Name);
                this.statsProcessedNumber++;
                this.rule.Process(context, obj);
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("An error occured while processing type {0}: {1}", typeof(T).FullName, e.ToString());
            }
        }

        private void LoadNewEntry(int lineNumber, String entry)
        {
            entry = entry.Trim();
            String[] parts = entry.Split(new char[] { ' ' }, 2);
            String command = parts[0].Trim().ToLower();
            String arg = "";
            if (parts.Length == 2)
            {
                arg = parts[1].Trim();
            }
            this.dynamic.ProcessCommand(lineNumber, entry, command, arg);
        }
    }
}
